package info.sean.util;


import info.sean.logger.GmfLogger;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @see ：DateUtils
 * @see ：扩展日期工具类
 *
 * @see ：   2015-6-24下午5:34:40
 * @author malong
 * 
 * @see ：
 * @see [编号：日期_设计来源]，[修改人：***]，[方法名：***]
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
	private static Logger logger = GmfLogger.getLogger(DateUtils.class);

	
	public static final String YYYYMMDD = "yyyyMMdd";
	public static final String YYMMDD = "yyMMdd";
	public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
	public static final String YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss SSS";
	private static final String defaultDatePattern = "yyyy-MM-dd";
//	public static final String YYYYMMDD = "yyyyMMdd";
	public static final String YYYYMMDD_EXT = "yyyy-MM-dd";
//	public static final String YYMMDD = "yyMMdd";
//	public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
	public static final String DEFAULT_PATTERN = "yyyy-MM-dd";
	
	/**
	 * 获得默认的 date pattern
	 */
	public static String getDatePattern() {
		return defaultDatePattern;
	}
	public static Date parse(String strDate,String pattern) {
		try {
			return StringUtils.isBlank(strDate) ? null :
				new SimpleDateFormat(pattern).parse(strDate);
		} catch (ParseException e) {
			throw new RuntimeException("Unable to parse the date: " + strDate + ", pattern:" + pattern);
		}
	}

	/**
	 * @see ：getLastDayOfMonth
	 * @see ：获得月底最后一天的日期
	 * @see ：2015-6-24下午5:34:55
	 * @author ChengChun
	 *  
	 * @param batchDate
	 * @return
	 * 
	 * @see ：
	 * @see [编号：日期]，[修改人：*** ]，[修改说明：***]
	 */
	public static Date getLastDayOfMonth(Date batchDate){
		Calendar c = Calendar.getInstance();
		c.setTime(batchDate);
		c.add(Calendar.MONTH, 1);
		c.set(Calendar.DATE, 1);
		c.add(Calendar.DATE, -1);
		return c.getTime();
	}
	
	/**
	 * @see ：getMonthInterval
	 * @see：获得给定两个日期之间相隔的月数，算到日
	 * @see ：2015-6-24下午5:35:07
	 * @author ChengChun
	 *  
	 * @param from
	 * @param to
	 * @return
	 * 
	 * @see ：
	 * @see [编号：日期]，[修改人：*** ]，[修改说明：***]
	 */
	public static int getMonthInterval(Date from,Date to){
		Calendar f = Calendar.getInstance();
		f.setTime(from);
		Calendar t = Calendar.getInstance();
		t.setTime(to);
		int year =t.get(Calendar.YEAR) - f.get(Calendar.YEAR);
		int month = t.get(Calendar.MONTH) - f.get(Calendar.MONTH);
		return year*12+month;
	}
	/**
	 * @see ：getIntervalDays
	 * @see ：获得两个日期间隔天数
	 * @see ：2015-6-24下午5:35:21
	 * @author ChengChun
	 *  
	 * @param from
	 * @param to
	 * @return
	 * 
	 * @see ：
	 * @see [编号：日期]，[修改人：*** ]，[修改说明：***]
	 */
	public static int getIntervalDays(Date from,Date to){
		long interval = truncate(to, Calendar.DATE).getTime()-truncate(from, Calendar.DATE).getTime();
		int result = (int)(interval/(1000*3600*24));
		return result;
	}
	
	/**
	 * @see ：isMonthEnd
	 * @see ：判断给定日期是否月底
	 * @see ：2015-6-24下午5:35:35
	 * @author ChengChun
	 *  
	 * @param date
	 * @return
	 * 
	 * @see ：
	 * @see [编号：日期]，[修改人：*** ]，[修改说明：***]
	 */
	public static boolean isMonthEnd(Date date){
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.DATE, 1);
		return c.get(Calendar.DATE) == 1;
	}
	
	/**
	 * 格式化日期
	 * @param date
	 * @param pattern
	 * @return
	 */
	public static String formatDate2String(Date date, String pattern){
		 if(date == null) {return null;}
		 SimpleDateFormat myFmt=new SimpleDateFormat(pattern);        
	     return myFmt.format(date);
	}
	
	/**
	 * @see ：fixYear
	 * @see ：b007补年
	 * @see ：2015-6-24下午4:57:01
	 * @author ChengChun
	 *  
	 * @param b007
	 * @param batchDate
	 * @return
	 * 
	 * @see ：
	 * @see [编号：日期]，[修改人：*** ]，[修改说明：***]
	 */
	public static Date fixYear(String b007, Date batchDate) {
		Calendar batchDateTime = Calendar.getInstance();
		//对于交易日期大于当前营业日期2天及以内的交易，视为正常交易，交易年份按当日顺推处理
		batchDateTime.setTime(DateUtils.addDays(batchDate, 2));
		Calendar txnDateTime = Calendar.getInstance();
		txnDateTime.set(batchDateTime.get(Calendar.YEAR), 
						Integer.parseInt(b007.substring(0, 2)) -1, 
						Integer.parseInt(b007.substring(2, 4)), 
						Integer.parseInt(b007.substring(4, 6)), 
						Integer.parseInt(b007.substring(6, 8)), 
						Integer.parseInt(b007.substring(8, 10))); 
		if(txnDateTime.get(Calendar.DAY_OF_YEAR) > batchDateTime.get(Calendar.DAY_OF_YEAR)){
			txnDateTime.add(Calendar.YEAR, -1);
		}
		return txnDateTime.getTime();
	}
	
	/**
	 * 获取日期部分，如年，月，日，时，分秒，周第几天等等
	 * @param date
	 * @param item Calendar.YEAR/MONTH/DATE/HOUR/MINUTE/SECOND/DAY_OF_WEEK
	 */
	public static int getTimeByCalendar(Date date,int item){
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		
		//获取月份是特殊处理 +1
		if(Calendar.MONTH == item){
			return cal.get(item)+1;
		}
		
		return cal.get(item);
	}
	
	/**
	 * 给时间加上或减去指定毫秒，秒，分，时，天、月或年等，返回变动后的时间
	 * 
	 * @param date
	 *            要加减前的时间，如果不传，则为当前日期
	 * @param field
	 *            时间域，有Calendar.MILLISECOND,Calendar.SECOND,Calendar.MINUTE,<br>
	 *            Calendar.HOUR,Calendar.DATE, Calendar.MONTH,Calendar.YEAR
	 * @param amount
	 *            按指定时间域加减的时间数量，正数为加，负数为减。
	 * @return 变动后的时间
	 */
	public static Date add(Date date, int field, int amount) {
		if (date == null) {
			date = new Date();
		}

		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(field, amount);

		return cal.getTime();
	}
	

	/**
	 * 拼接获得业务日期的时间: 业务/批量日期 + 自然时间的时分秒
	 * 
	 * @param bizDate
	 * @return
	 */
	public static Date parseBusinessTime(Date bizDate) {
		if(bizDate==null){
			return null;
		}
		// 业务日期
		Calendar biz = Calendar.getInstance();
		biz.setTimeInMillis(bizDate.getTime());
		// 当前时间
		Calendar now = Calendar.getInstance();
		// 设置时分秒
		biz.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY));
		biz.set(Calendar.MINUTE, now.get(Calendar.MINUTE));
		biz.set(Calendar.SECOND, now.get(Calendar.SECOND));

		return biz.getTime();
	}
	
	/**
	 * 判断middDate是否在startDate,endDate区间，不包含等于
	 *
	 * @param startDate
	 * @param middDate
	 * @param endDate
	 * @return boolean
	 * @exception
	 * @since 1.0.0
	 */
	public static boolean dateBetwen(String startDate, String middDate, String endDate) {
		return dateCompare(middDate, startDate) > 0 && dateCompare(endDate, middDate) > 0;
	}

	/**
	 * 判断middDate是否在startDate,endDate区间，包含等于
	 *
	 * @param startDate
	 * @param middDate
	 * @param endDate
	 * @return boolean
	 * @exception
	 * @since 1.0.0
	 */
	public static boolean dateBetwen(Date startDate, Date middDate, Date endDate) {
		return dateCompare(middDate, startDate) > 0 && dateCompare(endDate, middDate) >= 0;
	}

	/**
	 * 日期比较
	 * 
	 * @param date1
	 * @param date2
	 * @return int date1 > date2 =1；date1 = date2 =0；date1 <date2 =-1
	 * @exception
	 * @since 1.0.0
	 */
	public static int dateCompare(String date1, String date2) {
		int i = 0;
		SimpleDateFormat sm = new SimpleDateFormat("yyyy-MM-dd");
		try {
			i = sm.parse(date1).compareTo(sm.parse(date2));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return i;
	}
	
	/**
	 * 日期比较
	 * 
	 * @param date1
	 * @param date2
	 * @return int date1 > date2 =1；date1 = date2 =0；date1 <date2 =-1
	 * @exception
	 * @since 1.0.0
	 */
	public static int dateTimeCompare(String date1, String date2) {
		int i = 0;
		SimpleDateFormat sm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try {
			i = sm.parse(date1).compareTo(sm.parse(date2));
		} catch (ParseException e) {

		}
		return i;
	}
	/**
	 * 日期比较
	 *
	 * @param date1
	 * @param date2
	 * @return int date1 > date2 =1；date1 = date2 =0；date1 <date2 =-1
	 * @exception
	 * @since 1.0.0
	 */
	public static int dateCompare(Date date1, Date date2) {
		int i = 0;
		SimpleDateFormat sm = new SimpleDateFormat("yyyy-MM-dd");
		String bigenDate = sm.format(date1);
		String endDate = sm.format(date2);
		sm.format(date2);
		try {
			i = sm.parse(bigenDate).compareTo(sm.parse(endDate));
		} catch (ParseException e) {
			 e.printStackTrace();
		}
		return i;
	}
	/**
	 * 用批量日期计算逾期期数
	 * @param overDueDate
	 * @param overDueDate
	 * @return
	 */
	public static int countOverDueTerm(Date overDueDate, Date batchDate){
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTime(overDueDate);
		int month1 = calendar1.get(Calendar.MONTH);
		Calendar calendar2 = Calendar.getInstance();
		calendar2.setTime(batchDate);
		int month2 = calendar2.get(Calendar.MONTH);
		int interval = month2-month1;
		int year =calendar2.get(Calendar.YEAR) - calendar1.get(Calendar.YEAR);
		
		if(interval>=0){
			calendar1.add(Calendar.MONTH, interval);
			int days = calendar2.get(Calendar.DAY_OF_MONTH)-calendar1.get(Calendar.DAY_OF_MONTH);
			if(days<0){
				//还没到一个月
			}else{
				//到了一个月
				interval++;
			}
		}
		return year*12+interval;
	}
	/**
	 * 获取下一个固定日期
	 * 如固定日期为20号，则获取下一个即将到来的20号
	 * @param targetDate
	 * @param fixedDay
	 * @return
	 */
	public static Date nextFixedDayOfMonth(Date targetDate, int fixedDay) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(targetDate);
		int currDay = calendar.get(Calendar.DAY_OF_MONTH);
		if(currDay>=fixedDay) {//说明已经过了当月的该固定日
			calendar.set(Calendar.DAY_OF_MONTH, fixedDay);
			calendar.add(Calendar.MONTH, 1);
		}else {
			calendar.set(Calendar.DAY_OF_MONTH, fixedDay);
		}
		return calendar.getTime();
	}
	/**
	 * 获得指定日期的前一天
	 * @param dateSpecified
	 * @return
	 * @throws Exception
	 */
	public static Date getSpecifiedDayBefore(Date dateSpecified) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String specifiedDay = simpleDateFormat.format(dateSpecified);
		Calendar c = Calendar.getInstance();
		Date date=null;
		Date specifiedDate = null;
		try {
			date = new SimpleDateFormat("yy-MM-dd").parse(specifiedDay);
			c.setTime(date);
			int day=c.get(Calendar.DATE);
			c.set(Calendar.DATE,day-1);
			String dayBefore=new SimpleDateFormat("yyyy-MM-dd").format(c.getTime());
			specifiedDate = simpleDateFormat.parse(dayBefore);
		} catch (ParseException e) {
			e.printStackTrace();
		}

		return specifiedDate;
	}
	public static Date getThreeDaysBefore(Date date){
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
		String dateStr = simpleDateFormat.format(date);
		Calendar c = Calendar.getInstance();
		try {
			c.setTime(simpleDateFormat.parse(dateStr));
			c.set(Calendar.DATE,c.get(Calendar.DATE)-3);
			return c.getTime();
		} catch (ParseException e) {
			throw new RuntimeException("getThreeDaysBefore failed");
		}
	}

	public static String parseByMillisecond(long time) {
		return new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS_SSS).format(new Date(time));
	}

	//获取日期在该年的天数
	public static String getDayOfYear(Date date) {
		String day = String.format("%td", date);
		String month = String.format("%tm",date);
		String year = String.format("%tY", date);
		return year+"_"+month+day;
	}

	//获取时间年月日进行拼接查询23点到23:59:59数据
	public static String getYearMonthDay(Date date) {
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");//Date指定格式：yyyy-MM-dd HH:mm:ss:SSS
		String dateStr = simpleDateFormat.format(date);//format()方法将Date转换成指定格式的String
		return "'"+dateStr+"'";
	}

	public static Date getLastMonthStart(Date date){
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Calendar cale = Calendar.getInstance();
		cale.setTime(date);
		cale.add(Calendar.MONTH, -1);
		cale.set(Calendar.DAY_OF_MONTH, 1);
		String firstday = format.format(cale.getTime());
		try {
			Date  lastMonthStart = format.parse(firstday);
			return lastMonthStart;
		} catch (ParseException e) {
			throw new RuntimeException("getLastMonthStart failed");
		}
	}

	public static Date getLastMonthEnd(Date date){
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		Calendar cale = Calendar.getInstance();
		cale.setTime(date);
		cale.set(Calendar.DAY_OF_MONTH, 0);
		String lastday = format.format(cale.getTime());
		try {
			Date  lastMonthEnd = format.parse(lastday);
			return lastMonthEnd;
		} catch (ParseException e) {
			throw new RuntimeException("getLastMonthEnd failed");
		}
	}

	/**
	 * 计算上一个月的总天数
	 * @param bizDate
	 * @return
	 */
	public static int getLastMonthDays(Date bizDate) {
		Date  lastMonthStart = getLastMonthEnd(bizDate);
		Calendar cale = Calendar.getInstance();
		cale.setTime(lastMonthStart);
		return cale.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	public static void main(String[] args) {

		Date nowDate = new Date();
		Date  lastMonthStart = getLastMonthStart(nowDate);
		System.out.println("lastMonthStart:"+lastMonthStart);
		Date  lastMonthEnd = getLastMonthEnd(nowDate);
		System.out.println("lastMonthEnd:"+lastMonthEnd);
		int  days = getLastMonthDays(nowDate);
		System.out.println("last month days:"+days);
		System.out.println(getStartOfDay(nowDate));
		System.out.println(getEndOfDay(nowDate));
		String dateStr = "2022-08-22";
		Date parseDateTime = parseDateTime(dateStr);
		System.out.println("parseDateTime = " + parseDateTime);
	}

	/**
	 * 获取指定日期上个月第一天
	 * @param date
	 * @return
	 */
	public static Date getLastMonthFirstDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH,-1);
		calendar.set(Calendar.DAY_OF_MONTH,1);
		calendar.set(Calendar.HOUR_OF_DAY,0);
		calendar.set(Calendar.MINUTE,0);
		calendar.set(Calendar.SECOND,0);
		return calendar.getTime();
	}

	/**
	 * 获取指定日期上个月最后一天
	 * @param date
	 * @return
	 */
	public static Date getLastMonthFinalDay(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
        calendar.add(Calendar.MONTH,- 1);
		calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		calendar.set(Calendar.HOUR_OF_DAY,23);
		calendar.set(Calendar.MINUTE,59);
		calendar.set(Calendar.SECOND,59);
		return calendar.getTime();
	}

	public static String getDateTimeMSEL() {
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
		return LocalDateTime.now(ZoneOffset.of("+8")).format(formatter);

	}
	/**
	 * 获取两个日期之间的所有日期(包涵begin,end)
	 */
	public static List<Date> getBetweenDates(Date begin, Date end) {
		List<Date> result = new ArrayList<>();
		Calendar tempStart = Calendar.getInstance();
		tempStart.setTime(begin);
		while(begin.getTime()<=end.getTime()){
			result.add(tempStart.getTime());
			tempStart.add(Calendar.DAY_OF_MONTH, 1);
			begin = tempStart.getTime();
		}
		return result;
	}

	/**
	 * 给定日期是否是当年的最后一天
	 * */
	public static boolean isYearLastDay(Date date){
		Calendar calendar=Calendar.getInstance();
		calendar.setTime(date);
		int year = calendar.get(Calendar.YEAR);
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.roll(Calendar.DAY_OF_YEAR, -1);
		Date currYearLast = calendar.getTime();
		return  dateCompare(date,currYearLast) == 0;
	}

	/**
	 *
	 * @description: 获得当天最小时间
	 * @param date
	 * @return
	 */

	public static Date getStartOfDay(Date date) {
		LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()),ZoneId.systemDefault());
		LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
		return Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant());
	}

	/**
	 * @description: 获得当天最大时间
	 * @param date
	 * @return
	 */

	public static Date getEndOfDay(Date date) {
		LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()),ZoneId.systemDefault());
		LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
		return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
	}


	/**
	 * 格式化 date 为相应 pattern 字符串 ， 若 pattern 为 null 则赋予默认 pattern
	 */
	public static String formatDate(Date date,String pattern){
		if(pattern == null){ pattern = DEFAULT_PATTERN; }
		return date == null ? "" : new SimpleDateFormat(pattern).format(date);
	}

	/**
	 * 格式化 date 返回一个 DEFAULT_PATTERN 的 字符串
	 */
	public static String formatDateTime(Date date){
		return date == null ? "" : new SimpleDateFormat(DEFAULT_PATTERN).format(date);
	}

	/**
	 * 返回当前日期的  DEFAULT_PATTERN 字符串
	 */
	public static String getTodayTime(){
		return formatDateTime(new Date());
	}



	/**
	 * 将 dateStr 解析为  DEFAULT_PATTERN  的  Date
	 */
	public static Date parseDateTime(String dateStr) {
		try {
			return StringUtils.isBlank(dateStr) ? null : new SimpleDateFormat(DEFAULT_PATTERN).parse(dateStr);
		} catch (ParseException e) {
			logger.error("Date parse exception,dateStr:{},pattern:{}",dateStr,DEFAULT_PATTERN);
			throw new RuntimeException(e);
		}
	}

	/**
	 * 将 dateStr 解析为 相应 pattern 的 Date，若 pattern 为 null，则赋予 DEFAULT_PATTERN
	 */
	public static Date parseDate(String dateStr,String pattern)  {
		if(pattern == null){ pattern = DEFAULT_PATTERN; }
		try {
			return StringUtils.isBlank(dateStr) ? null : new SimpleDateFormat(pattern).parse(dateStr);
		} catch (ParseException e) {
			logger.error("Date parse exception,dateStr:{},pattern:{}",dateStr,pattern);
			throw new RuntimeException(e);
		}
	}

}
